#include <stdlib.h>

#include <stdio.h>
#include <iostream>
#include <string>
#include <sstream>

using namespace std;


int B;
string generate_block_rules(int d);
string generate_arm_rules(int d);

string convertInt(int number)
{
   ostringstream ss;//create a stringstream
   ss << number;//add number to the stream
   return ss.str();//return a string with the contents of the stream
}
int main(int argc, char *argv[])
{
    if (argc < 2)
    {
      cout << "provide B as an argument please." <<endl;
      return -1;
    }

    B=atoi(argv[1]);
    //ibm_generate_K_arrow_psvn(K);
    string havij;
    string domain="BLK";
    havij = havij+"# list of domains\n";
    havij = havij+"Domain "+domain+" "+convertInt(B+1)+"\n";
    havij = havij+ "\t";
    for (int i=0;i<B+1;i++)
        havij= havij+convertInt(i)+" ";
    havij = havij+"\n\n# hand_holds under_1? on_1? under_2? on_2? ...\n";
    havij=havij+convertInt(2*B+1)+"\n\n";
    havij = havij+"# 0==holds_nothing 0==under_nothing 0==over_nothing\n";
    for (int i=0;i<2*B+1;i++)
        havij=havij+domain+" ";
    havij=havij+"\n\n";

    for (int d=1; d<=B; d++)
    {
        havij=havij+generate_arm_rules(d);
	havij += "\n";
    }
    for (int d=1; d<=B; d++)
    {
        havij = havij+generate_block_rules(d);
	havij += "\n";
    }

    havij=havij+"GOAL ";
    // for arm
    havij= havij+"0 ";
    for (int i=1;i<=B;i++){
        // under each block is i-1
        havij=havij+ convertInt(i-1)+" ";
	// over each block is i+1
	// excluding the last block that has 0 over it
	if(i==B)
	    havij= havij+"0 ";
	else
	    havij=havij+ convertInt(i+1)+" ";
    }
    havij=havij+"\n";
    cout << havij;

    return (EXIT_SUCCESS);
}


string generate_block_rules(int d)//d \in [1, B]
{
    string tstr1="";
    string tstr2="";
    string res_str="";
    int left[2*B+1];
    int right[2*B+1];

    // this is the when block d is in the hand
   

    // it can always be moved to the table
    res_str =  res_str+convertInt(d);
    res_str = res_str + " ";
    for (int z=1; z<=B; z++)// we do not care about other blocks
    {
        if(z != d)
        	res_str = res_str + "- - ";
	else // the current block should be clear (well, clear does not mean much for a block that is in the hand)
		res_str = res_str + "- - ";
    }
  
    res_str = res_str + "=> ";
    // hand is empty
    res_str = res_str + "0 ";
    // the other tiles will remain at their whatever position
    for (int z=1; z<=B; z++)// we do not care about other blocks
    {
       if(z==d)
		res_str = res_str + "- 0 ";
       else
	       res_str = res_str + "- - ";
    } 
    res_str = res_str + "\n";


    // now for moving the block to top of every other block
    for (int z1=1; z1<=B; z1++)// we do not care about other blocks
    {
       if(z1 == d) // cannot move the block to the top of itself
	  continue;
       // block d is in the hand
       res_str =  res_str+convertInt(d);
       res_str = res_str + " ";
       
       for (int z2 =1; z2<=B ;z2++){
	   // both your block and the z1 one should be clear
	   // d is on the table, so clear does not mean anything
           if (z2 == z1 /*|| z2 == d*/)
		res_str = res_str + "- 0 ";	
	   else
		res_str = res_str + "- - ";
       }
      
       res_str = res_str + "=> ";

       // hand is empty
       res_str =  res_str+ "0 ";
       
       
       for (int z2 =1; z2<=B ;z2++){
	   if (z2 == d){ // the block will be clear and on top of z1
		res_str = res_str + convertInt(z1);
		res_str = res_str + " - ";

	   }
	   else if (z2 == z1){ // the block is not clear anymore 
		res_str = res_str + "- ";
		res_str = res_str + convertInt(d);
		res_str = res_str + " ";

	   }
           else
		res_str = res_str + "- - ";
		
       }
       res_str = res_str + "\n";
    } 
 
    return res_str;
}

// rules for moving something to the arm
// if a block is clear and arm is clear move it to the arm
string generate_arm_rules(int d)//d \in [1, B]
{
    string tstr1="";
    string tstr2="";
    string res_str="";
    int left[2*B+1];
    int right[2*B+1];

   // when block d is on the table
    // hand is empty
    res_str = res_str + "0 ";
    for (int z=1; z<=B; z++)// we do not care about other blocks
    {
        if(z != d)
        	res_str = res_str + "- - ";
	else // the current block should be clear
		res_str = res_str + "0 0 ";
    }
  
    res_str = res_str + "=> ";
    // hand contains d
    res_str = res_str + convertInt(d);
    res_str = res_str + " ";
    // the other tiles will remain at their whatever position
    for (int z=1; z<=B; z++)// we do not care about other blocks
    {
         res_str = res_str + "- - ";
    } 
    res_str = res_str + "\n";


    // now for moving the clear block z1 which is on top of z2 to the arm
    for (int z1=1; z1<=B; z1++)
    {
       if(z1 == d) // block cannot be on top of itself
	  continue;
       // arm is clear
       res_str = res_str + "0 ";
       
       for (int z2 =1; z2<=B ;z2++){
	   // z1 should be clear and on top of z2
           if (z2 == d){
		res_str = res_str + convertInt(z1);
		res_str = res_str + " 0 ";
	   }	
	   else if (z2 == z1){
		// we can just do not care that the z1 is on top of z2 (we have already checked the other way around), but we do

		res_str = res_str + "- ";
		res_str = res_str + convertInt(d);		
		res_str = res_str + " ";		
	   }
 	   else
		res_str = res_str + "- - ";
       }
      
       res_str = res_str + "=> ";

       // hand will contain d
	res_str = res_str + convertInt(d);
	res_str = res_str + " ";       
       
       for (int z2 =1; z2<=B ;z2++){
	   // z1 should be clear and on top of z2
  /*         if (z2 == d){
		res_str = res_str + convertInt(z1);
		res_str = res_str + " 0 ";
	   }	
	   else
*/	   if (z2 == z1){ // the top of the block should be clear
		res_str = res_str + "- 0 ";
	   }
 	   else
		res_str = res_str + "- - ";
		
       }
       res_str = res_str + "\n";
    } 
 
    return res_str;
}
